package com.baidu.mpks.security;


import com.baidu.mpks.exception.BusinessException;
import com.baidu.mpks.permission.domain.Permission;
import com.baidu.mpks.permission.service.PermissionService;
import com.baidu.mpks.role.service.RoleService;
import com.baidu.mpks.user.domain.User;
import com.baidu.mpks.user.service.UserService;
import com.baidu.mpks.usergroup.dto.Resources;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Component
public class ApplicationRealm extends AuthorizingRealm {
    private static final Logger log = LoggerFactory.getLogger(ApplicationRealm.class);
    @Autowired
    @Lazy
    UserService userService;
    @Autowired
    @Lazy
    RoleService roleService;
    @Autowired
    @Lazy
    PermissionService permissionService;

    public ApplicationRealm() {
    }

    public AuthorizationInfo getAuthorizationInfo() {
        return super.getAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }

    private void logout(PrincipalCollection principals) {
        this.doClearCache(principals);
        SecurityUtils.getSubject().logout();
    }

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (!SecurityUtils.getSubject().isAuthenticated()) {
            this.logout(principals);
            return null;
        } else {
            User user = (User)principals.getPrimaryPrincipal();
            if (user == null) {
                return null;
            } else {
                User existUser = this.userService.findByUserId(user.getUserId());
                if (existUser != null && !existUser.getStatus().equals("Close")) {
                    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                    List<Resources> roles = this.userService.getUserAllRoles(user.getUserId());
                    Set<Integer> roleIds = (Set)roles.stream().map(Resources::getId).collect(Collectors.toSet());
                    Set<String> stringRoles = (Set)roles.stream().map(Resources::getName).collect(Collectors.toSet());
                    info.setRoles(stringRoles);
                    if (CollectionUtils.isNotEmpty(stringRoles) && stringRoles.contains("超级管理员")) {
                        info.setStringPermissions((Set)this.permissionService.findAll(1, 1000).stream().map(Permission::getCode).collect(Collectors.toSet()));
                        return info;
                    } else {
                        Set<String> stringPermissions = new HashSet();
                        stringPermissions.addAll(this.permissionService.findPermissionCodesByRoleIds(roleIds));
                        info.setStringPermissions(stringPermissions);
                        return info;
                    }
                } else {
                    this.logout(principals);
                    return null;
                }
            }
        }
    }

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        String account = token.getUsername();
        if (StringUtils.isEmpty(account)) {
            throw new BusinessException("登录名不能为空");
        } else {
            User user = this.userService.findByAccount(token.getUsername());
            if (user != null && "Open".equals(user.getStatus())) {
                String credentials = user.getPassword();
                ByteSource salt = ByteSource.Util.bytes(user.getUserId());
                return new SimpleAuthenticationInfo(user, credentials, salt, this.getName());
            } else {
                throw new BusinessException("用户无效");
            }
        }
    }

    public void clearAuthz() {
        log.info("userInfo: {}", SecurityUtils.getSubject().getPrincipals());
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }
}